package org.example;


import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.*;

/**
 * 分布式锁实现类
 * 实现java.util.concurrent.locks.Lock接口
 * 同步锁和异步锁
 *
 * @author fxab
 * @date 2025/04/06
 */

public class RedisLock implements Lock {
    private final RedisClient client;
    private final String key;
    private final String value; // 锁唯一标识
    private final int ttl;      // 锁有效期（秒）

    /**
     * redis锁
     *
     * @param client 客户
     * @param key    钥匙
     * @param ttl    ttl
     */
    public RedisLock(RedisClient client, String key, int ttl) {
        this.client = client;
        this.key = key;
        this.value = UUID.randomUUID().toString(); // 生成唯一标识
        this.ttl = ttl;
    }


    /**
     * 尝试获取同步锁
     */
    @Override
    public void lock() {
        while (!tryLock()) {
            try {
                Thread.sleep(100); // 重试间隔
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
    }

    /**
     * 中断锁定
     * 和 lock()方法相似, 但阻塞的线程可中断
     *
     * @throws InterruptedException 中断异常
     */
    @Override
    public void lockInterruptibly() throws InterruptedException {
        while (!tryLock()) {
            if (Thread.interrupted()) {
                throw new InterruptedException();
            }
            Thread.sleep(100);
        }
    }

    /**
     * 尝试获取锁(单次)
     *
     * @return boolean
     */
    @Override
    public boolean tryLock() {
        return client.tryLock(key, value, ttl);
    }

    /**
     * 尝试锁定
     *
     * @param time 时间
     * @param unit 单位
     * @return boolean
     * @throws InterruptedException 中断异常
     */
    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        long endTime = System.currentTimeMillis() + unit.toMillis(time);
        while (System.currentTimeMillis() < endTime) {
            if (tryLock()) {
                return true;
            }
            Thread.sleep(100);
        }
        return false;
    }

    /**
     * 解锁
     */
    @Override
    public void unlock() {
        client.unlock(key, value);
    }

    /**
     * 新条件
     *
     * @return {@link Condition }
     */
    @Override
    public Condition newCondition() {
        throw new UnsupportedOperationException("RedisLock不支持条件变量");
    }
}